/****************************************************
          File Name:49-1.c
          Author: Abby Cin
          Mail: abbytsing@gmail.com
          Created Time: Wed 17 Sep 2014 03:32:28 PM CST
*****************************************************/
/* using mmap() memcpy() ftruncate() instead of read() write() to write a 'cp' program */
#include<stdio.h>
#include<sys/mman.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<string.h>      /* memcpy */
#include<unistd.h>
#include<errno.h>
#include<stdlib.h>

void err(char *fun)
{
    perror(fun);
    exit(errno);
}

int main(int argc,char *argv[])
{
    if(argc<3)
    {
        printf("%s oldfile newfile\n",argv[0]);
        exit(EXIT_FAILURE);
    }

    struct stat tmp;
    int oldfd, newfd;

    if((oldfd=open(argv[1],O_RDWR))==-1)
        err("open oldfile");
    
    fstat(oldfd,&tmp);

    if((newfd=open(argv[2],O_CREAT|O_RDWR,00644))==-1)
        err("open newfile");
    /* if NOT make a empty file before line 51 will receive SIGBUS from kernel */
    if(ftruncate(newfd,tmp.st_size)==-1)
        err("ftuncate");
    
    void *oldaddr, *newaddr;

    oldaddr=mmap(NULL,tmp.st_size,PROT_READ,MAP_SHARED,oldfd,0);
    if(oldaddr==MAP_FAILED)
        err("mmap");
    newaddr=mmap(NULL,tmp.st_size,PROT_WRITE,MAP_SHARED,newfd,0);
    if(newaddr==MAP_FAILED)
        err("mmap");
    if(memcpy(newaddr,oldaddr,tmp.st_size)==NULL)
        err("memcpy");
    
    if(msync(newaddr,tmp.st_size,MS_SYNC)==-1)
        err("msync");

    exit(EXIT_SUCCESS);
}
